package cn.com.xf.service.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import cn.com.xf.dao.TblCheckDataDAO;
import cn.com.xf.dao.TblCheckHolidayDAO;
import cn.com.xf.dao.TblCheckLeaveDAO;
import cn.com.xf.dao.TblCheckMendDAO;
import cn.com.xf.dao.TblCheckReportDAO;
import cn.com.xf.dao.TblCheckScheduleDAO;
import cn.com.xf.dao.TblCheckShiftDAO;
import cn.com.xf.domain.TblCheckData;
import cn.com.xf.domain.TblCheckHoliday;
import cn.com.xf.domain.TblCheckLeave;
import cn.com.xf.domain.TblCheckMend;
import cn.com.xf.domain.TblCheckReport;
import cn.com.xf.domain.TblCheckSchedule;
import cn.com.xf.domain.TblCheckShift;
import cn.com.xf.service.KqfxService;
import cn.com.xf.utils.DateUtils;

@Service
public class KqfxServiceImpl implements KqfxService {

	@Autowired
	private ThreadPoolTaskExecutor taskExecutor;
	@Autowired
	private TblCheckScheduleDAO scheduleDAO;
	@Autowired
	private TblCheckShiftDAO shiftDAO;
	@Autowired
	private TblCheckMendDAO mendDAO;
	@Autowired
	private TblCheckLeaveDAO leaveDAO;	
	@Autowired
	private TblCheckDataDAO checkDataDAO;
	@Autowired
	private TblCheckHolidayDAO holidayDAO;
	@Autowired
	private TblCheckReportDAO reportDAO;

	public int analyze(final String[] userids, final Date startDate, final Date endDate) {
		String siteid = userids[0].substring(0,  6);
		List<Future<Integer>> tasks = new ArrayList<>();
		final List<TblCheckData> checkDataList = checkDataDAO.selectCheckDataByUseridsAndDate(userids, startDate,
				endDate);
		final List<TblCheckMend> mendList = mendDAO.selectMendByUseridsAndCheckdate(userids, startDate, endDate);
		final List<TblCheckLeave> leaveList = leaveDAO.selectLeaveByUserids(userids);
		final List<TblCheckSchedule> scheduleList = scheduleDAO.selectScheduleByUserids(userids);
		final List<TblCheckHoliday> holidayList = holidayDAO.selectBySiteid(siteid);
		final List<TblCheckReport> updateList = new ArrayList<>();
		final List<TblCheckReport> insertList = new ArrayList<>();
		
		for (final String userid : userids) {
			final List<TblCheckData> userCheckDataList = new ArrayList<>();
			final List<TblCheckMend> userMendList = new ArrayList<>();
			final List<TblCheckLeave> userLeaveList = new ArrayList<>();
			final List<TblCheckSchedule> userScheduleList = new ArrayList<>();
			for (TblCheckData data : checkDataList) {
				if (data.getUserid().equals(userid)) {
					userCheckDataList.add(data);
				}
			}

			for (TblCheckMend data : mendList) {
				if (data.getUserid().equals(userid)) {
					userMendList.add(data);
				}
			}

			for (TblCheckLeave data : leaveList) {
				if (data.getUserid().equals(userid)) {
					userLeaveList.add(data);
				}
			}

			for (TblCheckSchedule data : scheduleList) {
				if (data.getUserid().equals(userid)) {
					userScheduleList.add(data);
				}
			}

			tasks.add(taskExecutor.submit(new Callable<Integer>() {

				@Override
				public Integer call() throws Exception {
					Calendar calendar = Calendar.getInstance();
					Date curDate = startDate;
					
					while (curDate.compareTo(endDate) <= 0) {
						long startTime = System.currentTimeMillis();
						double shouldHours = 0;
						double realHours = 0;
						double offworknum = 0; 
						double leavenum = 0;
						double realDays = 0;
						double holidaynum = 0;
						calendar.setTime(curDate);
						if (userMendList.size() > 0) {
							for (TblCheckMend mend : userMendList) {
								// 上班卡
								if (mend.getTime1() != null) {
									TblCheckData checkData = new TblCheckData();
									checkData.setCheckdate(curDate);
									checkData.setChecktime(mend.getTime1());
									checkData.setType((short) 0);
									userCheckDataList.add(checkData);
								}
								if (mend.getTime2() != null) {
									TblCheckData checkData = new TblCheckData();
									checkData.setCheckdate(curDate);
									checkData.setChecktime(mend.getTime2());
									checkData.setType((short) 0);
									userCheckDataList.add(checkData);
								}
								if (mend.getTime3() != null) {
									TblCheckData checkData = new TblCheckData();
									checkData.setCheckdate(curDate);
									checkData.setChecktime(mend.getTime3());
									checkData.setType((short) 0);
									userCheckDataList.add(checkData);
								}

							}
						}
						
						boolean isScheduled = false;
						TblCheckShift shift = new TblCheckShift();
						for (TblCheckSchedule schedule : userScheduleList) {
							if (schedule.getStartdate().compareTo(curDate) <= 0
									&& schedule.getEnddate().compareTo(curDate) >= 0) {
								isScheduled = true;
								shift = shiftDAO.selectShiftById(schedule.getShiftid());
								break;
							}
						}
						if (!isScheduled) {
							shift.setfCheckintime("08:30");
							shift.setfCheckedDays("0.5");
							shift.setsCheckintime("13:30");
							shift.setsCheckedDays("0.5");
						}

						
						Date fCheckintime = null, sCheckintime = null;
						if (shift.getfCheckintime() != null && !shift.getfCheckintime().equals(":"))
							fCheckintime = DateUtils.connectDateAndTime(curDate, shift.getfCheckintime());

						if (shift.getsCheckintime() != null && !shift.getsCheckintime().equals(":"))
							sCheckintime = DateUtils.connectDateAndTime(curDate, shift.getsCheckintime());
						boolean hasF = false;
						boolean hasS = false;
						
						boolean isFHoliday = false;
						boolean isSHoliday = false;
						for (TblCheckHoliday holiday: holidayList) {
							if (holiday.getStartdate().compareTo(fCheckintime) <= 0 && holiday.getEnddate().compareTo(fCheckintime) >= 0) {
								isFHoliday = true;
								hasF = true;
							}
							if (holiday.getStartdate().compareTo(sCheckintime) <= 0 && holiday.getEnddate().compareTo(sCheckintime) >= 0) {
								isSHoliday = true;
								hasS = true;
							}
							if (isFHoliday && isSHoliday)
								break;
						}
						
						if (isFHoliday) {
							holidaynum += Double.parseDouble(shift.getfCheckedDays());
						}
						
						if (isSHoliday) {
							holidaynum += Double.parseDouble(shift.getsCheckedDays());
						}
						
						for (TblCheckData data : userCheckDataList) {
							if (data.getCheckdate().compareTo(curDate) == 0) {
								long fDelta = Math.abs(data.getChecktime().getTime() - fCheckintime.getTime());
								long sDelta = Math.abs(data.getChecktime().getTime() - sCheckintime.getTime());
									
								if (!hasF && !isFHoliday && fDelta < 1000 * 60 * 60 * 3) {
									realDays += Double.parseDouble(shift.getfCheckedDays());
									hasF = true;
								}
								
								if (!hasS && !isSHoliday && sDelta < 1000 * 60 * 60 * 3) {
									realDays += Double.parseDouble(shift.getsCheckedDays());
									hasS = true;
								}
								
								break;

							}
						}
						
						
						if (!hasF) {
							boolean isLeave = false;
							for (TblCheckLeave leave: userLeaveList) {
								if (leave.getStartdate().compareTo(fCheckintime) <= 0 && leave.getEnddate().compareTo(fCheckintime) >=0) {
									isLeave = true;
									leavenum += Double.parseDouble(shift.getfCheckedDays());
									break;
								}
							}
							if (!isLeave)
								offworknum += Double.parseDouble(shift.getfCheckedDays());
						}
						if (!hasS) {
							boolean isLeave = false;
							for (TblCheckLeave leave: userLeaveList) {
								if (leave.getStartdate().compareTo(sCheckintime) <= 0 && leave.getEnddate().compareTo(sCheckintime) >=0) {
									isLeave = true;
									leavenum += Double.parseDouble(shift.getsCheckedDays());
									break;
								}
							}
							if (!isLeave)
								offworknum += Double.parseDouble(shift.getsCheckedDays());
						}
						

						TblCheckReport report = reportDAO.selectByUseridAndCheckdate(userid, curDate);
						if (report != null) {
							report.setLeavenum(leavenum);
							report.setOffworknum(offworknum);
							report.setHolidaynum(holidaynum);
							report.setRealDays(realDays);
							report.setShouldHours(shouldHours);
							report.setRealHours(realHours);
							report.setSiteid(userid.substring(0, 6));
							report.setCheckdate(curDate);
							//reportDAO.updateByPrimaryKey(report);
							updateList.add(report);
						} else {
							report = new TblCheckReport();
							report.setUserid(userid);
							report.setCheckdate(curDate);
							report.setLeavenum(leavenum);
							report.setOffworknum(offworknum);
							report.setHolidaynum(holidaynum);
							report.setRealDays(realDays);
							report.setShouldHours(shouldHours);
							report.setRealHours(realHours);
							report.setSiteid(userid.substring(0, 6));
							//reportDAO.insert(report);
							insertList.add(report);
						}
						calendar.add(Calendar.DATE, 1);
						curDate = calendar.getTime();
					}
					return 1;
				}
			}));
		}

		while (true) {
			boolean isAllDone = true;
			for (Future<Integer> taskResult : tasks) {
				isAllDone &= (taskResult.isDone() || taskResult.isCancelled());
			}
			if (isAllDone) {
				try {
					reportDAO.insertBatch(insertList);
					reportDAO.updateBatch(updateList);
				} catch (Exception e) {
					e.printStackTrace();
				}
				break;
			}
		}

		return 1;
	}
}
